import { defineStore } from 'pinia'
import { checkIsCanPlay, getMusicSource, getMusicDetail, getLyric } from '@/api/song'
import type { MusicSong, Lrc } from '@/types/song/index'
import { useLyric } from '@/hooks/useLyric'
import type { LrcRes } from '@/hooks/useLyric'

const { formatLrc } = useLyric()

export const usePlayerStore = defineStore('player', {
  state: () => {
    return {
      audio: new Audio(), //audio标签
      loopType: 0, //循环模式 0 单曲循环 1 列表循环 2随机播放
      volume: 100, //音量
      status: 'pause' as 'pause' | 'playing', //播放状态 playing pause
      muted: false, //是否静音
      ended: false, //是否结束
      currentTime: 0, //当前播放时间
      duration: 0, //总时长
      id: 0, // 音乐id
      url: '', //url
      isShowPlayList: false, //是否展示播放列表
      isShowLyricList: false, //是否展示歌词列表
      musicInfo: {} as MusicSong, //歌曲详情
      lrc: {} as Lrc, //歌词
      sliderValue: 0, //进度条当前的时间
      formattedLrc: [] as Array<LrcRes>, //格式化后的歌词
      isAudition: false, //是否试听
      playList: [] as MusicSong[], //播放列表
    }
  },
  getters: {
    playListCount(): number {
      return this.playList.length
    },
  },
  actions: {
    /**
     * 重置仓库
     */
    clear() {
      this.status = 'pause'
      this.audio.pause()
      this.audio.src = ''
      this.currentTime = 0
      this.duration = 0
      this.id = 0
      this.url = ''
      this.musicInfo = {} as MusicSong
      this.lrc = {} as Lrc
      this.sliderValue = 0
      this.formattedLrc = []
      this.isAudition = false
      this.playList = []
    },
    /**
     * 控制循环条件
     */
    toggleLoop() {
      if (this.loopType === 2) {
        this.loopType = 0
      } else {
        this.loopType++
      }
    },

    /**
     * 点击前一首
     */
    togglePrev() {},

    /**
     * 点击播放暂停
     */
    async togglePlay() {
      if (!this.id) return
      if (this.status === 'pause') {
        this.status = 'playing'
        await this.audio.play()
      } else {
        this.status = 'pause'
        this.audio.pause()
      }
    },

    /**
     * 点击下一首
     */
    toggleNext() {},

    /**
     * 点击静音
     */
    toggleMuted() {
      this.muted = !this.muted
      this.audio.muted = this.muted
    },

    /**
     * 调节音量
     */
    setVolume(value: number) {
      this.volume = value
      this.audio.volume = value / 100
    },

    /**
     * 播放歌曲
     */
    async play() {
      const res = await getMusicSource(this.id)
      const { data, code } = res.data
      if (code !== 200) return ElMessage.error('播放失败')
      this.audio.src = data[0].url
      // 是否试听
      this.isAudition = data[0]?.freeTrialInfo?.end > 0
      this.audio.play().then((res) => {
        this.status = 'playing'
        this.url = data[0].url
        this.duration = data[0].time
      })
      await this.musicDetail()
      await this.getMusicLrc()
    },

    /**
     * 检查音乐能否播放
     * @returns
     */
    async checkSource() {
      return new Promise<boolean>(async (resolve, reject) => {
        try {
          const res = await checkIsCanPlay(this.id)
          resolve(res.data.success)
        } catch (error) {
          resolve(false)
          ElMessage.error(error as any)
        }
      })
    },

    /**
     * 控制展示playList
     * @param value
     */
    setPlayListStatus(value: boolean) {
      this.isShowPlayList = value
    },
    /**
     * 控制展示lyricList
     * @param value
     */
    setLyricStatus(value: boolean) {
      if (!this.id) return
      this.isShowLyricList = value
    },

    /**
     * 设置id
     */
    setId(id: number) {
      this.id = id
      this.play()
    },

    /**
     * 获取歌曲详情
     */
    async musicDetail() {
      const { data } = await getMusicDetail(this.id)
      if (data.code !== 200) return ElMessage.error('获取失败')
      this.musicInfo = data.songs[0]
    },

    /**
     * 获取歌词
     */
    async getMusicLrc() {
      const { data } = await getLyric(this.id)
      if (data.code !== 200) return ElMessage.error('获取失败')
      this.lrc = data.lrc
      this.formattedLrc = formatLrc(this.lrc?.lyric ?? '')
    },

    /**
     * 监听 audio 的 timeUpdate
     */
    timeUpdate(fn?: Function) {
      this.audio.ontimeupdate = (e) => {
        this.calcSliderProgress()
        fn && fn()
      }
    },

    /**
     * 计算进度条
     */
    calcSliderProgress() {
      // audio 的 currentTime 以秒为单位 服务端返回的是毫秒为单位
      this.currentTime = parseInt((this.audio.currentTime * 1000).toString())
      this.sliderValue = (this.currentTime / this.duration) * 100
    },

    /**
     * 监听 audio 的 ended 事件
     */
    ended() {
      this.audio.addEventListener('ended', () => {
        this.audio.pause()
        this.status = 'pause'
        this.controlPlayListByLoop()
      })
    },

    /**
     * 根据循环模式和播放列表控制是否播放下一曲
     */
    controlPlayListByLoop() {
      const idx = this.playList.findIndex((item) => item.id === this.id)
      // 单曲循环
      if (this.loopType === 0) {
        this.setId(this.id)
      }
      // 列表循环
      else if (this.loopType === 1) {
        // 列表最后一首
        if (idx === this.playList.length - 1) {
          this.setId(this.playList[0].id)
        } else {
          const id = this.playList[idx + 1].id
          this.setId(id)
        }
      }
    },

    /**
     * 暴露一个全局方法，在 app 启动时监听 audio 一些事件
     */
    initPlayer() {
      this.timeUpdate()
      this.ended()
    },

    /**
     * 改变进度条进度
     */
    changeProgress(e: any) {
      this.currentTime = (e / 100) * this.duration
      this.audio.currentTime = this.currentTime / 1000
    },

    /**
     * 向播放列表里添加音乐
     */
    async addPlayList(id: number, replace: boolean = false) {
      const idx = this.playList.findIndex((item) => item.id === id)
      if (idx !== -1) return ElMessage.info('播放列表已存在~')
      const { data } = await getMusicDetail(id)
      if (data.code !== 200) return ElMessage.error('获取失败')
      this.playList.push(data.songs[0])
      // 如果没有在播放且播放列表只有一首歌直接播放
      if (this.status === 'pause' && this.playList.length === 1) {
        this.setId(id)
      }
    },
  },
})
